package com.darkevil.jdspider.utils

import org.apache.http.HttpEntity
import org.apache.http.NameValuePair
import org.apache.http.client.config.RequestConfig
import org.apache.http.client.entity.UrlEncodedFormEntity
import org.apache.http.client.methods.CloseableHttpResponse
import org.apache.http.client.methods.HttpGet
import org.apache.http.client.methods.HttpPost
import org.apache.http.conn.ssl.DefaultHostnameVerifier
import org.apache.http.conn.util.PublicSuffixMatcherLoader
import org.apache.http.entity.ContentType
import org.apache.http.entity.StringEntity
import org.apache.http.entity.mime.MultipartEntityBuilder
import org.apache.http.entity.mime.content.FileBody
import org.apache.http.entity.mime.content.StringBody
import org.apache.http.impl.client.CloseableHttpClient
import org.apache.http.impl.client.HttpClients
import org.apache.http.message.BasicNameValuePair
import org.apache.http.util.EntityUtils
import org.slf4j.LoggerFactory
import org.springframework.stereotype.Service
import java.io.File
import java.io.FileOutputStream
import java.io.IOException
import java.net.URL
import java.util.*

@Service
class HttpClientUtil {
    companion object {
//        var instance: HttpClientUtil? = null
//            get() {
//                if (field == null) instance = HttpClientUtil()
//                return field
//            }
        private val logger = LoggerFactory.getLogger(HttpClientUtil::class.java)
    }

    private val requestConfig = RequestConfig.custom()
            .setSocketTimeout(30000)
            .setConnectTimeout(30000)
            .setConnectionRequestTimeout(60000)
            .build()

    private var httpClient: CloseableHttpClient? = null
        get() {
            if (field == null) {
                field = HttpClients.custom().setMaxConnTotal(5000).setMaxConnPerRoute(5000).build()
            }
            return field
        }

    /**
     * 发送 post请求
     *
     * @param httpUrl 地址
     */
    fun sendHttpPost(httpUrl: String, charset: String = "UTF-8"): String? {
        val httpPost = HttpPost(httpUrl)// 创建httpPost
        return sendHttpPost(httpPost, charset)
    }

    /**
     * 发送 post请求
     *
     * @param httpUrl 地址
     * @param params  参数(格式:key1=value1&key2=value2)
     */
    fun sendHttpPost(httpUrl: String, params: String, isJson: Boolean = true, token: String? = null, headers: Map<String, String>? = null, charset: String = "UTF-8"): String? {
        val httpPost = HttpPost(httpUrl)// 创建httpPost
        try {
            //设置参数
            val stringEntity = StringEntity(params, "UTF-8")
            if (isJson) {
                stringEntity.setContentType("application/json")
            } else {
                stringEntity.setContentType("application/x-www-form-urlencoded")
            }
            if (token?.isNotBlank() == true) {
                httpPost.addHeader("Authorization", "Bearer $token")
            }
            //设置header
            headers?.forEach { key, value -> httpPost.addHeader(key, value) }
            httpPost.entity = stringEntity
        } catch (e: Exception) {
            e.printStackTrace()
            throw e
        }
        logger.debug("""
            请求url：$httpUrl
            请求方式：POST
            请求body：$params
        """.trimIndent())
        return sendHttpPost(httpPost, charset)
    }

    /**
     * 发送 post请求
     *
     * @param httpUrl 地址
     * @param maps    参数
     */
    fun sendHttpPost(httpUrl: String, maps: Map<String, String>, charset: String = "UTF-8"): String? {
        val httpPost = HttpPost(httpUrl)// 创建httpPost
        // 创建参数队列
        val nameValuePairs = ArrayList<NameValuePair>()
        maps.forEach { key, value -> nameValuePairs.add(BasicNameValuePair(key, value)) }
        try {
            httpPost.entity = UrlEncodedFormEntity(nameValuePairs, "UTF-8")
        } catch (e: Exception) {
            e.printStackTrace()
            throw e
        }

        return sendHttpPost(httpPost, charset)
    }


    /**
     * 发送 post请求（带文件）
     *
     * @param httpUrl       地址
     * @param maps          参数
     * @param fileListMap     附件,格式为Map<附件的字段></附件的字段>，附件文件列表>
     */
    fun sendHttpPost(httpUrl: String, maps: Map<String, String>, fileListMap: Map<String, List<File>>): String? {
        val httpPost = HttpPost(httpUrl)// 创建httpPost
        val meBuilder = MultipartEntityBuilder.create()
        for (key in maps.keys) {
            meBuilder.addPart(key, StringBody(maps[key], ContentType.create("application/x-www-form-urlencoded", "utf-8")))
        }
        /**
         * 遍历文件map
         * fileFieldName 文件所属字段
         * fileList 文件列表
         */
        fileListMap.forEach { t, u ->
            u.forEach { file ->
                val fileBody = FileBody(file)
                meBuilder.addPart(t, fileBody)
            }
        }
        val reqEntity = meBuilder.build()
        httpPost.entity = reqEntity
        return sendHttpPost(httpPost)
    }

    /**
     * 发送Post请求
     *
     * @param httpPost
     * @return
     */
    private fun sendHttpPost(httpPost: HttpPost, charset: String = "UTF-8"): String? {
//        var httpClient: CloseableHttpClient? = null
        var response: CloseableHttpResponse? = null
        val entity: HttpEntity?
        var responseContent: String? = null
        try {
            // 创建默认的httpClient实例.
            val httpClient = this.httpClient
            httpPost.config = requestConfig
            // 执行请求
            response = httpClient!!.execute(httpPost)
            entity = response!!.entity
            responseContent = EntityUtils.toString(entity!!, charset)
        } catch (e: IllegalStateException) {
            this.httpClient = null
            sendHttpPost(httpPost)
        } catch (e: Exception) {
            e.printStackTrace()
            throw e
        } finally {
            try {
                // 关闭连接,释放资源
                response?.close()
                httpClient?.close()
            } catch (e: IOException) {
                e.printStackTrace()
            }

        }
        return responseContent
    }

    /**
     * 发送 get请求
     *
     * @param httpUrl
     */
    fun sendHttpGet(httpUrl: String, token: String? = null, headers: Map<String, String>? = null, charset: String = "UTF-8"): String? {
        val httpGet = HttpGet(httpUrl)// 创建get请求
        if (token?.isNotBlank() == true) {
            httpGet.addHeader("Authorization", "Bearer $token")
        }
        //设置header
        headers?.forEach { key, value -> httpGet.addHeader(key, value) }
        return sendHttpGet(httpGet, charset)
    }

    /**
     * 发送GET请求，并将响应写入文件
     *
     * @param httpUrl
     * @param filePath
     */
    fun sendHttpGetToFile(httpUrl: String, filePath: String) {
        val httpGet = HttpGet(httpUrl)// 创建get请求
        val file = File(filePath)
        sendHttpGetToFile(httpGet, file)
    }

    /**
     * 发送 get请求Https
     *
     * @param httpUrl
     */
    fun sendHttpsGet(httpUrl: String, charset: String = "UTF-8"): String? {
        val httpGet = HttpGet(httpUrl)// 创建get请求
        return sendHttpsGet(httpGet, charset)
    }

    /**
     * 手动关闭httpClient，释放资源
     */
    fun closeHttpCient() {
        httpClient?.close()
        httpClient = null
    }

    /**
     * 发送Get请求
     *
     * @param httpGet
     * @return
     */
    private fun sendHttpGet(httpGet: HttpGet, charset: String = "UTF-8"): String? {
//        var httpClient: CloseableHttpClient? = null
        var response: CloseableHttpResponse? = null
        val entity: HttpEntity?
        var responseContent: String? = null
        try {
            // 创建默认的httpClient实例.
            val httpClient = this.httpClient
            httpGet.config = requestConfig
            // 执行请求
            response = httpClient!!.execute(httpGet)
            entity = response!!.entity
            responseContent = EntityUtils.toString(entity!!, charset)
        } catch (e: IllegalStateException) {
            this.httpClient = null
            sendHttpGet(httpGet)
        } catch (e: Exception) {
            e.printStackTrace()
            throw e
        } finally {
            try {
                // 关闭连接,释放资源
                response?.close()
//                httpClient?.close()
            } catch (e: IOException) {
                e.printStackTrace()
            }

        }
        return responseContent
    }

    /**
     * 发送Get请求
     *
     * @param httpGet
     */
    private fun sendHttpGetToFile(httpGet: HttpGet, file: File) {
        var response: CloseableHttpResponse? = null
        val entity: HttpEntity?
        val responseBytes: ByteArray?
        try {
            // 创建默认的httpClient实例.
            val httpClient = this.httpClient
            httpGet.config = requestConfig
            // 执行请求
            response = httpClient!!.execute(httpGet)
            entity = response!!.entity
            responseBytes = EntityUtils.toByteArray(entity!!)
            writeFile(responseBytes, file)
        } catch (e: IllegalStateException) {
            this.httpClient = null
            sendHttpGetToFile(httpGet, file)
        } catch (e: Exception) {
            e.printStackTrace()
            throw e
        } finally {
            try {
                // 关闭连接,释放资源
                response?.close()
//                httpClient?.close()
//                if (httpClient != null) {
//                    httpClient.close()
//                }
            } catch (e: IOException) {
                e.printStackTrace()
            }

        }
    }

    private fun writeFile(bytes: ByteArray?, file: File) {
        if (!file.exists()) {
            try {
                file.createNewFile()
            } catch (e: IOException) {
                e.printStackTrace()
            }

        }
        var fileOutputStream: FileOutputStream? = null
        try {
            fileOutputStream = FileOutputStream(file)
            fileOutputStream.write(bytes!!)
            fileOutputStream.flush()
        } catch (e: IOException) {
            e.printStackTrace()
            throw e
        } finally {
            if (fileOutputStream != null) {
                try {
                    fileOutputStream.close()
                } catch (e: IOException) {
                    e.printStackTrace()
                }

            }
        }

    }

    /**
     * 发送Get请求Https
     *
     * @param httpGet
     * @return
     */
    private fun sendHttpsGet(httpGet: HttpGet, charset: String = "UTF-8"): String? {
        var httpClient: CloseableHttpClient? = null
        var response: CloseableHttpResponse? = null
        val entity: HttpEntity?
        val responseContent: String?
        try {
            // 创建默认的httpClient实例.
            val publicSuffixMatcher = PublicSuffixMatcherLoader.load(URL(httpGet.uri.toString()))
            val hostnameVerifier = DefaultHostnameVerifier(publicSuffixMatcher)
            httpClient = HttpClients.custom().setSSLHostnameVerifier(hostnameVerifier).build()
            httpGet.config = requestConfig
            // 执行请求
            response = httpClient!!.execute(httpGet)
            entity = response!!.entity
            responseContent = EntityUtils.toString(entity!!, charset)
        } catch (e: Exception) {
            e.printStackTrace()
            throw e
        } finally {
            try {
                // 关闭连接,释放资源
                response?.close()
//                httpClient?.close()
            } catch (e: IOException) {
                e.printStackTrace()
            }

        }
        return responseContent
    }
}

